﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RMCharGen.Character;

namespace RMCharGen.UI
{
    internal partial class StatisticsGrid : UserControl
    {
        private const string NullCharacterError = "The Character property has not been set.";

        private bool _allowEdits = false;


        /// <summary>
        /// Provides the numeric only values in the editing cells
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StatisticsView_EditingControlShowing(object sender,
                                                                DataGridViewEditingControlShowingEventArgs e)
        {
            if (this.StatisticsView.CurrentCell.ColumnIndex == 1 ||
                this.StatisticsView.CurrentCell.ColumnIndex == 2)
            {
                if (e.Control is TextBox)
                {
                    TextBox editControl = e.Control as TextBox;
                    editControl.KeyPress -= new KeyPressEventHandler(NumericCell_KeyPress);
                    editControl.KeyPress += new KeyPressEventHandler(NumericCell_KeyPress);
                    editControl.MaxLength = 3;
                }
            }
        }

        /// <summary>
        /// Prevents non numeric keys being entered into the cell
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void NumericCell_KeyPress(object sender,
                                  KeyPressEventArgs e)
        {
            if (!char.IsDigit(e.KeyChar))
            {
                Keys key = (Keys)e.KeyChar;
                if ((!(key == Keys.Back ||
                      key == Keys.Delete)) ||
                      e.KeyChar == '.')
                {
                    e.Handled = true;
                }
            }
        }

        #region " Setup Statistics grid "

        /// <summary>
        /// Creates the DataGridViewCellStyle for read-only cells
        /// </summary>
        /// <returns></returns>
        private DataGridViewCellStyle CreateReadOnlyCellStyle()
        {
            DataGridViewCellStyle readOnlyCellStyle = new DataGridViewCellStyle();

            readOnlyCellStyle.BackColor = Color.LightSteelBlue;
            readOnlyCellStyle.Font = new Font(StatisticsView.Font, FontStyle.Bold);

            return readOnlyCellStyle;
        }

        /// <summary>
        /// Sets the correct styles to the cells in the grid
        /// </summary>
        private void StyleGrid()
        {
            DataGridViewCellStyle readOnlyStyle = CreateReadOnlyCellStyle();

            for (int index = 0; index < 10; index++)
            {
                StatisticsView.Rows[index].Cells[0].Style = readOnlyStyle;

                StatisticsView.Rows[index].Cells[1].ValueType = typeof(int);
                StatisticsView.Rows[index].Cells[2].ValueType = typeof(int);
            }

            for (int index = 5; index < 10; index++)
            {
                StatisticsView.Rows[index].Cells[3].Style = readOnlyStyle;
            }
        }

        /// <summary>
        /// Adds the Statistic Names to the first column in the correct rows
        /// </summary>
        private void AddStatNames()
        {
            StatisticsView.Rows[0].Cells[0].Value = "Constitution";
            StatisticsView.Rows[1].Cells[0].Value = "Agility";
            StatisticsView.Rows[2].Cells[0].Value = "Self Discipline";
            StatisticsView.Rows[3].Cells[0].Value = "Memory";
            StatisticsView.Rows[4].Cells[0].Value = "Reasoning";
            StatisticsView.Rows[5].Cells[0].Value = "Strength";
            StatisticsView.Rows[6].Cells[0].Value = "Quickness";
            StatisticsView.Rows[7].Cells[0].Value = "Presence";
            StatisticsView.Rows[8].Cells[0].Value = "Intuition";
            StatisticsView.Rows[9].Cells[0].Value = "Empathy";
        }

        /// <summary>
        /// Make the required columns in the grid read-only
        /// </summary>
        private void LockDownGrid()
        {
            StatisticsView.AllowUserToAddRows = false;
            StatisticsView.AllowUserToDeleteRows = false;
            StatisticsView.AllowUserToOrderColumns = false;
            StatisticsView.AllowUserToResizeRows = false;
            StatisticsView.AllowUserToResizeColumns = false;

            if (this.AllowEdits)
            {
                StatisticsView.ReadOnly = false;
                StatisticsView.EditMode = DataGridViewEditMode.EditOnEnter;
                StatisticsView.Columns[0].ReadOnly = true;
                StatisticsView.Columns[1].ReadOnly = false;
                StatisticsView.Columns[2].ReadOnly = false;
                StatisticsView.Columns[3].ReadOnly = true;
                StatisticsView.Columns[4].ReadOnly = true;
                StatisticsView.Columns[5].ReadOnly = true;
                StatisticsView.Columns[6].ReadOnly = true;
                StatisticsView.Columns[7].ReadOnly = true;
            }
            else
            {
                StatisticsView.ReadOnly = true;
            }
        }

        private void InititialiseStatisticsGrid()
        {
            StatisticsView.Rows.Add(10);

            AddStatNames();
            StyleGrid();
            LockDownGrid();
        }

        #endregion

        #region " Bind Statistics Grid "

        private void BindActuals()
        {
            StatisticsView.Rows[0].Cells[1].Value = this.Character.Statistics[StatisticType.CO].Actual;
            StatisticsView.Rows[1].Cells[1].Value = this.Character.Statistics[StatisticType.AG].Actual;
            StatisticsView.Rows[2].Cells[1].Value = this.Character.Statistics[StatisticType.SD].Actual;
            StatisticsView.Rows[3].Cells[1].Value = this.Character.Statistics[StatisticType.Me].Actual;
            StatisticsView.Rows[4].Cells[1].Value = this.Character.Statistics[StatisticType.Re].Actual;
            StatisticsView.Rows[5].Cells[1].Value = this.Character.Statistics[StatisticType.St].Actual;
            StatisticsView.Rows[6].Cells[1].Value = this.Character.Statistics[StatisticType.Qu].Actual;
            StatisticsView.Rows[7].Cells[1].Value = this.Character.Statistics[StatisticType.Pr].Actual;
            StatisticsView.Rows[8].Cells[1].Value = this.Character.Statistics[StatisticType.In].Actual;
            StatisticsView.Rows[9].Cells[1].Value = this.Character.Statistics[StatisticType.EM].Actual;
        }

        private void BindPotentials()
        {
            StatisticsView.Rows[0].Cells[2].Value = this.Character.Statistics[StatisticType.CO].Potential;
            StatisticsView.Rows[1].Cells[2].Value = this.Character.Statistics[StatisticType.AG].Potential;
            StatisticsView.Rows[2].Cells[2].Value = this.Character.Statistics[StatisticType.SD].Potential;
            StatisticsView.Rows[3].Cells[2].Value = this.Character.Statistics[StatisticType.Me].Potential;
            StatisticsView.Rows[4].Cells[2].Value = this.Character.Statistics[StatisticType.Re].Potential;
            StatisticsView.Rows[5].Cells[2].Value = this.Character.Statistics[StatisticType.St].Potential;
            StatisticsView.Rows[6].Cells[2].Value = this.Character.Statistics[StatisticType.Qu].Potential;
            StatisticsView.Rows[7].Cells[2].Value = this.Character.Statistics[StatisticType.Pr].Potential;
            StatisticsView.Rows[8].Cells[2].Value = this.Character.Statistics[StatisticType.In].Potential;
            StatisticsView.Rows[9].Cells[2].Value = this.Character.Statistics[StatisticType.EM].Potential;
        }

        private void BindDevelopmentPoints()
        {
            StatisticsView.Rows[0].Cells[3].Value = this.Character.Statistics[StatisticType.CO].DevelopmentPoints;
            StatisticsView.Rows[1].Cells[3].Value = this.Character.Statistics[StatisticType.AG].DevelopmentPoints;
            StatisticsView.Rows[2].Cells[3].Value = this.Character.Statistics[StatisticType.SD].DevelopmentPoints;
            StatisticsView.Rows[3].Cells[3].Value = this.Character.Statistics[StatisticType.Me].DevelopmentPoints;
            StatisticsView.Rows[4].Cells[3].Value = this.Character.Statistics[StatisticType.Re].DevelopmentPoints;
        }

        private void BindNormalBonus()
        {
            StatisticsView.Rows[0].Cells[4].Value = this.Character.Statistics[StatisticType.CO].NormalBonus;
            StatisticsView.Rows[1].Cells[4].Value = this.Character.Statistics[StatisticType.AG].NormalBonus;
            StatisticsView.Rows[2].Cells[4].Value = this.Character.Statistics[StatisticType.SD].NormalBonus;
            StatisticsView.Rows[3].Cells[4].Value = this.Character.Statistics[StatisticType.Me].NormalBonus;
            StatisticsView.Rows[4].Cells[4].Value = this.Character.Statistics[StatisticType.Re].NormalBonus;
            StatisticsView.Rows[5].Cells[4].Value = this.Character.Statistics[StatisticType.St].NormalBonus;
            StatisticsView.Rows[6].Cells[4].Value = this.Character.Statistics[StatisticType.Qu].NormalBonus;
            StatisticsView.Rows[7].Cells[4].Value = this.Character.Statistics[StatisticType.Pr].NormalBonus;
            StatisticsView.Rows[8].Cells[4].Value = this.Character.Statistics[StatisticType.In].NormalBonus;
            StatisticsView.Rows[9].Cells[4].Value = this.Character.Statistics[StatisticType.EM].NormalBonus;
        }

        private void BindRaceBonus()
        {
            StatisticsView.Rows[0].Cells[5].Value = this.Character.Statistics[StatisticType.CO].RaceBonus;
            StatisticsView.Rows[1].Cells[5].Value = this.Character.Statistics[StatisticType.AG].RaceBonus;
            StatisticsView.Rows[2].Cells[5].Value = this.Character.Statistics[StatisticType.SD].RaceBonus;
            StatisticsView.Rows[3].Cells[5].Value = this.Character.Statistics[StatisticType.Me].RaceBonus;
            StatisticsView.Rows[4].Cells[5].Value = this.Character.Statistics[StatisticType.Re].RaceBonus;
            StatisticsView.Rows[5].Cells[5].Value = this.Character.Statistics[StatisticType.St].RaceBonus;
            StatisticsView.Rows[6].Cells[5].Value = this.Character.Statistics[StatisticType.Qu].RaceBonus;
            StatisticsView.Rows[7].Cells[5].Value = this.Character.Statistics[StatisticType.Pr].RaceBonus;
            StatisticsView.Rows[8].Cells[5].Value = this.Character.Statistics[StatisticType.In].RaceBonus;
            StatisticsView.Rows[9].Cells[5].Value = this.Character.Statistics[StatisticType.EM].RaceBonus;
        }

        private void BindMiscellaneousBonus()
        {
            StatisticsView.Rows[0].Cells[6].Value = this.Character.Statistics[StatisticType.CO].MiscellaneousBonus;
            StatisticsView.Rows[1].Cells[6].Value = this.Character.Statistics[StatisticType.AG].MiscellaneousBonus;
            StatisticsView.Rows[2].Cells[6].Value = this.Character.Statistics[StatisticType.SD].MiscellaneousBonus;
            StatisticsView.Rows[3].Cells[6].Value = this.Character.Statistics[StatisticType.Me].MiscellaneousBonus;
            StatisticsView.Rows[4].Cells[6].Value = this.Character.Statistics[StatisticType.Re].MiscellaneousBonus;
            StatisticsView.Rows[5].Cells[6].Value = this.Character.Statistics[StatisticType.St].MiscellaneousBonus;
            StatisticsView.Rows[6].Cells[6].Value = this.Character.Statistics[StatisticType.Qu].MiscellaneousBonus;
            StatisticsView.Rows[7].Cells[6].Value = this.Character.Statistics[StatisticType.Pr].MiscellaneousBonus;
            StatisticsView.Rows[8].Cells[6].Value = this.Character.Statistics[StatisticType.In].MiscellaneousBonus;
            StatisticsView.Rows[9].Cells[6].Value = this.Character.Statistics[StatisticType.EM].MiscellaneousBonus;
        }

        private void BindTotalBonus()
        {
            StatisticsView.Rows[0].Cells[7].Value = this.Character.Statistics[StatisticType.CO].Total;
            StatisticsView.Rows[1].Cells[7].Value = this.Character.Statistics[StatisticType.AG].Total;
            StatisticsView.Rows[2].Cells[7].Value = this.Character.Statistics[StatisticType.SD].Total;
            StatisticsView.Rows[3].Cells[7].Value = this.Character.Statistics[StatisticType.Me].Total;
            StatisticsView.Rows[4].Cells[7].Value = this.Character.Statistics[StatisticType.Re].Total;
            StatisticsView.Rows[5].Cells[7].Value = this.Character.Statistics[StatisticType.St].Total;
            StatisticsView.Rows[6].Cells[7].Value = this.Character.Statistics[StatisticType.Qu].Total;
            StatisticsView.Rows[7].Cells[7].Value = this.Character.Statistics[StatisticType.Pr].Total;
            StatisticsView.Rows[8].Cells[7].Value = this.Character.Statistics[StatisticType.In].Total;
            StatisticsView.Rows[9].Cells[7].Value = this.Character.Statistics[StatisticType.EM].Total;
        }

        private void BindStatisticsGrid()
        {
            BindActuals();
            BindPotentials();
            BindDevelopmentPoints();
            BindNormalBonus();
            BindRaceBonus();
            BindMiscellaneousBonus();
            BindTotalBonus();
        }

        #endregion

        public StatisticsGrid()
        {
            InitializeComponent();
            InititialiseStatisticsGrid();
        }

        internal CharacterSheet Character
        {
            get;
            set;
        }

        internal bool AllowEdits
        {
            get
            {
                return this._allowEdits;
            }
            set
            {
                this._allowEdits = value;
                LockDownGrid();
            }
        }

        public void Bind()
        {
            if (this.Character == null)
            {
                throw new NullReferenceException(NullCharacterError);
            }
            else
            {
                BindStatisticsGrid();
            }
        }

        internal bool ValidCurrentValues()
        {
            bool valid = true;

            for (int row = 0; row < 10; row++)
            {
                if (StatisticsView.Rows[row].Cells[1].Value == null)
                {
                    valid = false;
                    break;
                }
            }

            return valid;
        }

        internal bool ValidValues()
        {
            bool valid = true;

            DataGridViewCellStyle invalidCellStyle = new DataGridViewCellStyle();

            invalidCellStyle.BackColor = Color.Tomato;
            invalidCellStyle.Font = new Font(StatisticsView.Font, FontStyle.Bold);

            for (int row = 0; row < 10; row++)
            {
                if (StatisticsView.Rows[row].Cells[1].Value == null)
                {
                    valid = false;
                    StatisticsView.Rows[row].Cells[1].Style = invalidCellStyle;
                }
                if (StatisticsView.Rows[row].Cells[2].Value == null)
                {
                    valid = false;
                    StatisticsView.Rows[row].Cells[2].Style = invalidCellStyle;
                }
                if (StatisticsView.Rows[row].Cells[1].Value != null &&
                    StatisticsView.Rows[row].Cells[2].Value != null)
                {
                    int current = (int)StatisticsView.Rows[row].Cells[1].Value;
                    int potential = (int)StatisticsView.Rows[row].Cells[2].Value;

                    if (current > potential)
                    {
                        valid = false;
                        StatisticsView.Rows[row].Cells[2].Style = invalidCellStyle;
                    }
                }
            }

            return valid;

        }

        private StatisticType DetermineStatistic(int row)
        {
            StatisticType statType = StatisticType.CO;

            switch (row)
            {
                case 1:
                    statType = StatisticType.AG;
                    break;
                case 2:
                    statType = StatisticType.SD;
                    break;
                case 3:
                    statType = StatisticType.Me;
                    break;
                case 4:
                    statType = StatisticType.Re;
                    break;
                case 5:
                    statType = StatisticType.St;
                    break;
                case 6:
                    statType = StatisticType.Qu;
                    break;
                case 7:
                    statType = StatisticType.Pr;
                    break;
                case 8:
                    statType = StatisticType.In;
                    break;
                case 9:
                    statType = StatisticType.EM;
                    break;
            }

            return statType;
        }

        private void StatisticsView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                Model.StatisticType statType = DetermineStatistic(e.RowIndex);
                this.Character.Statistics[statType].Actual = (int)StatisticsView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
                Bind();
            }
        }

    }
}
